﻿/*
 * Copyright (c) 1995 The Regents of the University of California.
 * All rights reserved.    
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice and the following
 * two paragraphs appear in all copies of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.    THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

/*
 * Portions of this software Copyright (c) 1995 Brown University.
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement
 * is hereby granted, provided that the above copyright notice and the
 * following two paragraphs appear in all copies of this software.
 * 
 * IN NO EVENT SHALL BROWN UNIVERSITY BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF BROWN
 * UNIVERSITY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * BROWN UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE.    THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
 * BASIS, AND BROWN UNIVERSITY HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
 * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 */

/*
Portions copyright (c) 2012 Eric Lasota

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/


using System;
using System.Collections.Generic;
using System.Text;

namespace MPEGnet
{
    public enum MBQuantType
    {
        False,
        True,
        Error
    }

    internal struct mb_addr_inc_entry
    {
        public int value;       /* value for macroblock_address_increment */
        public int num_bits;    /* length of the Huffman code */
    }

    /* Structure for an entry in the decoding table of macroblock_type */
    internal struct mb_type_entry
    {
        public bool mb_quant;              /* macroblock_quant */
        public bool mb_motion_forward;     /* macroblock_motion_forward */
        public bool mb_motion_backward;    /* macroblock_motion_backward */
        public bool mb_pattern;            /* macroblock_pattern */
        public bool mb_intra;              /* macroblock_intra */
        public int num_bits;               /* length of the Huffman code */
    }

    internal struct motion_vectors_entry
    {
        public int code;              /* value for motion_horizontal_forward_code,
			                           * motion_vertical_forward_code, 
			                           * motion_horizontal_backward_code, or
			                           * motion_vertical_backward_code.
			                           */
        public int num_bits;          /* length of the Huffman code */
    }

    /* Structure for an entry in the decoding table of dct_dc_size */
    internal struct VlcValue
    {
        public uint value;            /* value of dct_dc_size (luminance or chrominance) */
        public int num_bits;          /* length of the Huffman code */
        

        public static VlcValue[] InitVlcValues(uint[,] initializers)
        {
            int numValues = initializers.GetLength(0);
            VlcValue[] vlcValues = new VlcValue[numValues];
            for(int i=0;i<numValues;i++)
            {
                vlcValues[i].value = initializers[i,0];
                vlcValues[i].num_bits = (int)initializers[i,1];
            }
            return vlcValues;
        }
    }

    /* Structures for an entry in the decoding table of coded_block_pattern */
    internal struct coded_block_pattern_entry
    {
        uint cbp;                    /* coded_block_pattern */
        int num_bits;                /* length of the Huffman code */
    }

    internal class VlcTables
    {
        public const int ERROR = -1;
        public const uint UERROR = 0xffffffff;

        
        const uint DCT_ERROR = 63;

        const int MACRO_BLOCK_STUFFING = 34;
        const int MACRO_BLOCK_ESCAPE = 35;

        /* Two types of DCT Coefficients */
        const int DCT_COEFF_FIRST = 0;
        const int DCT_COEFF_NEXT = 1;

        /* Special values for DCT Coefficients */
        public const int END_OF_BLOCK = 62;
        public const int ESCAPE = 61;

        /*
           Changes to make the code reentrant:
             curVidStream now not global - DecodeDCT* functioned #ifdef'd out
               (are they needed?)
           Additional changes:
             none
           -lsh@cs.brown.edu (Loring Holden)
         */

        /* Decoding table for macroblock_address_increment */
        public static mb_addr_inc_entry[]     mb_addr_inc = new mb_addr_inc_entry[2048];

        /* Decoding table for macroblock_type in predictive-coded pictures */
        public static mb_type_entry[]         mb_type_P = new mb_type_entry[64];

        /* Decoding table for macroblock_type in bidirectionally-coded pictures */
        public static mb_type_entry[]         mb_type_B = new mb_type_entry[64];

        /* Decoding table for motion vectors */
        public static motion_vectors_entry[]  motion_vectors = new motion_vectors_entry[2048];

        /* Decoding table for coded_block_pattern */

        public static VlcValue[] coded_block_pattern = VlcValue.InitVlcValues(new uint[,]
        { {UERROR, 0}, {UERROR, 0}, {39, 9}, {27, 9}, {59, 9}, {55, 9}, {47, 9}, {31, 9},
            {58, 8}, {58, 8}, {54, 8}, {54, 8}, {46, 8}, {46, 8}, {30, 8}, {30, 8},
            {57, 8}, {57, 8}, {53, 8}, {53, 8}, {45, 8}, {45, 8}, {29, 8}, {29, 8},
            {38, 8}, {38, 8}, {26, 8}, {26, 8}, {37, 8}, {37, 8}, {25, 8}, {25, 8},
            {43, 8}, {43, 8}, {23, 8}, {23, 8}, {51, 8}, {51, 8}, {15, 8}, {15, 8},
            {42, 8}, {42, 8}, {22, 8}, {22, 8}, {50, 8}, {50, 8}, {14, 8}, {14, 8},
            {41, 8}, {41, 8}, {21, 8}, {21, 8}, {49, 8}, {49, 8}, {13, 8}, {13, 8},
            {35, 8}, {35, 8}, {19, 8}, {19, 8}, {11, 8}, {11, 8}, {7, 8}, {7, 8},
            {34, 7}, {34, 7}, {34, 7}, {34, 7}, {18, 7}, {18, 7}, {18, 7}, {18, 7},
            {10, 7}, {10, 7}, {10, 7}, {10, 7}, {6, 7}, {6, 7}, {6, 7}, {6, 7}, 
            {33, 7}, {33, 7}, {33, 7}, {33, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, 
            {9, 7}, {9, 7}, {9, 7}, {9, 7}, {5, 7}, {5, 7}, {5, 7}, {5, 7}, 
            {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, {63, 6}, 
            {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, {3, 6}, 
            {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, {36, 6}, 
            {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, {24, 6}, 
            {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5},
            {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5}, {62, 5},
            {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, 
            {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, {2, 5}, 
            {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, 
            {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, {61, 5}, 
            {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, 
            {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, {1, 5}, 
            {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, 
            {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, {56, 5}, 
            {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, 
            {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, {52, 5}, 
            {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, 
            {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, {44, 5}, 
            {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, 
            {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, {28, 5}, 
            {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, 
            {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, {40, 5}, 
            {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, 
            {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, {20, 5}, 
            {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, 
            {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, {48, 5}, 
            {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, 
            {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, 
            {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
            {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
            {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
            {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, {32, 4}, 
            {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
            {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
            {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
            {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, {16, 4}, 
            {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, 
            {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, 
            {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, 
            {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4}, {8, 4},
            {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4},
            {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, 
            {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, 
            {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4},
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, 
            {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}, {60, 3}
        } );

        /* Decoding tables for dct_dc_size_luminance */
        public static VlcValue[] dct_dc_size_luminance = VlcValue.InitVlcValues(new uint[,]
        {   {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
            {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
            {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, 
            {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}, {UERROR, 0}
        } );

        public static VlcValue[] dct_dc_size_luminance1 = VlcValue.InitVlcValues(new uint[,]
        {   {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6},
            {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10, 9}, {11, 9}
        } );

        /* Decoding table for dct_dc_size_chrominance */
        public static VlcValue[] dct_dc_size_chrominance = VlcValue.InitVlcValues(new uint[,]
        {   {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, 
            {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, 
            {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, 
            {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}, {UERROR, 0}
        } );

        public static VlcValue[] dct_dc_size_chrominance1 = VlcValue.InitVlcValues(new uint[,]
        {   {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, 
            {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, 
            {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, 
            {8, 8}, {8, 8}, {8, 8}, {8, 8}, {9, 9}, {9, 9}, {10, 10}, {11, 10}
        } );

        /* DCT coeff tables. */

        public static ushort[] dct_coeff_tbl_0 =
        {
        0xffff, 0xffff, 0xffff, 0xffff, 
        0xffff, 0xffff, 0xffff, 0xffff, 
        0xffff, 0xffff, 0xffff, 0xffff, 
        0xffff, 0xffff, 0xffff, 0xffff, 
        0x052f, 0x051f, 0x050f, 0x04ff, 
        0x183f, 0x402f, 0x3c2f, 0x382f, 
        0x342f, 0x302f, 0x2c2f, 0x7c1f, 
        0x781f, 0x741f, 0x701f, 0x6c1f, 
        0x028e, 0x028e, 0x027e, 0x027e, 
        0x026e, 0x026e, 0x025e, 0x025e, 
        0x024e, 0x024e, 0x023e, 0x023e, 
        0x022e, 0x022e, 0x021e, 0x021e, 
        0x020e, 0x020e, 0x04ee, 0x04ee, 
        0x04de, 0x04de, 0x04ce, 0x04ce, 
        0x04be, 0x04be, 0x04ae, 0x04ae, 
        0x049e, 0x049e, 0x048e, 0x048e, 
        0x01fd, 0x01fd, 0x01fd, 0x01fd, 
        0x01ed, 0x01ed, 0x01ed, 0x01ed, 
        0x01dd, 0x01dd, 0x01dd, 0x01dd, 
        0x01cd, 0x01cd, 0x01cd, 0x01cd, 
        0x01bd, 0x01bd, 0x01bd, 0x01bd, 
        0x01ad, 0x01ad, 0x01ad, 0x01ad, 
        0x019d, 0x019d, 0x019d, 0x019d, 
        0x018d, 0x018d, 0x018d, 0x018d, 
        0x017d, 0x017d, 0x017d, 0x017d, 
        0x016d, 0x016d, 0x016d, 0x016d, 
        0x015d, 0x015d, 0x015d, 0x015d, 
        0x014d, 0x014d, 0x014d, 0x014d, 
        0x013d, 0x013d, 0x013d, 0x013d, 
        0x012d, 0x012d, 0x012d, 0x012d, 
        0x011d, 0x011d, 0x011d, 0x011d, 
        0x010d, 0x010d, 0x010d, 0x010d, 
        0x282c, 0x282c, 0x282c, 0x282c, 
        0x282c, 0x282c, 0x282c, 0x282c, 
        0x242c, 0x242c, 0x242c, 0x242c, 
        0x242c, 0x242c, 0x242c, 0x242c, 
        0x143c, 0x143c, 0x143c, 0x143c, 
        0x143c, 0x143c, 0x143c, 0x143c, 
        0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 
        0x0c4c, 0x0c4c, 0x0c4c, 0x0c4c, 
        0x085c, 0x085c, 0x085c, 0x085c, 
        0x085c, 0x085c, 0x085c, 0x085c, 
        0x047c, 0x047c, 0x047c, 0x047c, 
        0x047c, 0x047c, 0x047c, 0x047c, 
        0x046c, 0x046c, 0x046c, 0x046c, 
        0x046c, 0x046c, 0x046c, 0x046c, 
        0x00fc, 0x00fc, 0x00fc, 0x00fc, 
        0x00fc, 0x00fc, 0x00fc, 0x00fc, 
        0x00ec, 0x00ec, 0x00ec, 0x00ec, 
        0x00ec, 0x00ec, 0x00ec, 0x00ec, 
        0x00dc, 0x00dc, 0x00dc, 0x00dc, 
        0x00dc, 0x00dc, 0x00dc, 0x00dc, 
        0x00cc, 0x00cc, 0x00cc, 0x00cc, 
        0x00cc, 0x00cc, 0x00cc, 0x00cc, 
        0x681c, 0x681c, 0x681c, 0x681c, 
        0x681c, 0x681c, 0x681c, 0x681c, 
        0x641c, 0x641c, 0x641c, 0x641c, 
        0x641c, 0x641c, 0x641c, 0x641c, 
        0x601c, 0x601c, 0x601c, 0x601c, 
        0x601c, 0x601c, 0x601c, 0x601c, 
        0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 
        0x5c1c, 0x5c1c, 0x5c1c, 0x5c1c, 
        0x581c, 0x581c, 0x581c, 0x581c, 
        0x581c, 0x581c, 0x581c, 0x581c, 
        };

        public static ushort[] dct_coeff_tbl_1 = 
        {
        0x00bb, 0x202b, 0x103b, 0x00ab, 
        0x084b, 0x1c2b, 0x541b, 0x501b, 
        0x009b, 0x4c1b, 0x481b, 0x045b, 
        0x0c3b, 0x008b, 0x182b, 0x441b, 
        };

        public static ushort[] dct_coeff_tbl_2 =
        {
        0x4019, 0x1429, 0x0079, 0x0839, 
        };

        public static ushort[] dct_coeff_tbl_3 = 
        {
        0x0449, 0x3c19, 0x3819, 0x1029, 
        };

        public static ushort[] dct_coeff_next = 
        {
        0xffff, 0xffff, 0xffff, 0xffff, 
        0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 
        0x0826, 0x0826, 0x2416, 0x2416, 
        0x0046, 0x0046, 0x2016, 0x2016, 
        0x1c15, 0x1c15, 0x1c15, 0x1c15, 
        0x1815, 0x1815, 0x1815, 0x1815, 
        0x0425, 0x0425, 0x0425, 0x0425, 
        0x1415, 0x1415, 0x1415, 0x1415, 
        0x3417, 0x0067, 0x3017, 0x2c17, 
        0x0c27, 0x0437, 0x0057, 0x2817, 
        0x0034, 0x0034, 0x0034, 0x0034, 
        0x0034, 0x0034, 0x0034, 0x0034, 
        0x1014, 0x1014, 0x1014, 0x1014, 
        0x1014, 0x1014, 0x1014, 0x1014, 
        0x0c14, 0x0c14, 0x0c14, 0x0c14, 
        0x0c14, 0x0c14, 0x0c14, 0x0c14, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0xfbe1, 0xfbe1, 0xfbe1, 0xfbe1, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        0x0011, 0x0011, 0x0011, 0x0011, 
        };

        public static ushort[] dct_coeff_first =
        {
        0xffff, 0xffff, 0xffff, 0xffff, 
        0xf7d5, 0xf7d5, 0xf7d5, 0xf7d5, 
        0x0826, 0x0826, 0x2416, 0x2416, 
        0x0046, 0x0046, 0x2016, 0x2016, 
        0x1c15, 0x1c15, 0x1c15, 0x1c15, 
        0x1815, 0x1815, 0x1815, 0x1815, 
        0x0425, 0x0425, 0x0425, 0x0425, 
        0x1415, 0x1415, 0x1415, 0x1415, 
        0x3417, 0x0067, 0x3017, 0x2c17, 
        0x0c27, 0x0437, 0x0057, 0x2817, 
        0x0034, 0x0034, 0x0034, 0x0034, 
        0x0034, 0x0034, 0x0034, 0x0034, 
        0x1014, 0x1014, 0x1014, 0x1014, 
        0x1014, 0x1014, 0x1014, 0x1014, 
        0x0c14, 0x0c14, 0x0c14, 0x0c14, 
        0x0c14, 0x0c14, 0x0c14, 0x0c14, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0023, 0x0023, 0x0023, 0x0023, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0813, 0x0813, 0x0813, 0x0813, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0412, 0x0412, 0x0412, 0x0412, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        0x0010, 0x0010, 0x0010, 0x0010, 
        };

        /* Macro for filling up the decoding table for mb_addr_inc */
        static int ASSIGN1(int start, int end, int step, int val, int num)
        {
            for (int i = start; i < end; i+= step)
            {
                for (int j = 0; j < step; j++)
                {
                    mb_addr_inc[i+j].value = val;
                    mb_addr_inc[i+j].num_bits = num;
                }
                val--;
            }
            return val;
        }

        /*
         *--------------------------------------------------------------
         *
         * init_mb_addr_inc --
         *
         *	Initialize the VLC decoding table for macro_block_address_increment
         *
         * Results:
         *	The decoding table for macro_block_address_increment will
         *      be filled; illegal values will be filled as ERROR.
         *
         * Side effects:
         *	The global array mb_addr_inc will be filled.
         *
         *--------------------------------------------------------------
         */
        static void init_mb_addr_inc()
        {
            int i, j, val;

            for (i = 0; i < 8; i++) {
                mb_addr_inc[i].value = (int)ERROR;
                mb_addr_inc[i].num_bits = 0;
            }

            mb_addr_inc[8].value = MACRO_BLOCK_ESCAPE;
            mb_addr_inc[8].num_bits = 11;

            for (i = 9; i < 15; i++) {
                mb_addr_inc[i].value = ERROR;
                mb_addr_inc[i].num_bits = 0;
            }

            mb_addr_inc[15].value = MACRO_BLOCK_STUFFING;
            mb_addr_inc[15].num_bits = 11;

            for (i = 16; i < 24; i++) {
                mb_addr_inc[i].value = ERROR;
                mb_addr_inc[i].num_bits = 0;
            }

            val = 33;

            val = ASSIGN1(24, 36, 1, val, 11);
            val = ASSIGN1(36, 48, 2, val, 10);
            val = ASSIGN1(48, 96, 8, val, 8);
            val = ASSIGN1(96, 128, 16, val, 7);
            val = ASSIGN1(128, 256, 64, val, 5);
            val = ASSIGN1(256, 512, 128, val, 4);
            val = ASSIGN1(512, 1024, 256, val, 3);
            val = ASSIGN1(1024, 2048, 1024, val, 1);
        }


        /* Macro for filling up the decoding table for mb_type */
        static void ASSIGN2(int start, int end, int quant, int motion_forward, int motion_backward, int pattern, int intra, int num, mb_type_entry[] mb_type)
        {
            for (int i = start; i < end; i ++)
            {
                mb_type[i].mb_quant = (quant != 0);
                mb_type[i].mb_motion_forward = (motion_forward != 0);
                mb_type[i].mb_motion_backward = (motion_backward != 0);
                mb_type[i].mb_pattern = (pattern != 0);
                mb_type[i].mb_intra = (intra != 0);
                mb_type[i].num_bits = num;
            }
        }


        /*
         *--------------------------------------------------------------
         *
         * init_mb_type_P --
         *
         *	Initialize the VLC decoding table for macro_block_type in
         *      predictive-coded pictures.
         *
         * Results:
         *	The decoding table for macro_block_type in predictive-coded
         *      pictures will be filled; illegal values will be filled as ERROR.
         *
         * Side effects:
         *	The global array mb_type_P will be filled.
         *
         *--------------------------------------------------------------
         */
        static void init_mb_type_P()
        {
            int i;

            mb_type_P[0].mb_quant = false;
            mb_type_P[0].mb_motion_forward 
                = mb_type_P[0].mb_motion_backward = mb_type_P[0].mb_pattern 
                = mb_type_P[0].mb_intra = false;
            mb_type_P[0].num_bits = 0;

            ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_P);
            ASSIGN2(2, 4, 1, 0, 0, 1, 0, 5, mb_type_P);
            ASSIGN2(4, 6, 1, 1, 0, 1, 0, 5, mb_type_P);
            ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_P);
            ASSIGN2(8, 16, 0, 1, 0, 0, 0, 3, mb_type_P);
            ASSIGN2(16, 32, 0, 0, 0, 1, 0, 2, mb_type_P);
            ASSIGN2(32, 64, 0, 1, 0, 1, 0, 1, mb_type_P);
        }




        /*
         *--------------------------------------------------------------
         *
         * init_mb_type_B --
         *
         *	Initialize the VLC decoding table for macro_block_type in
         *      bidirectionally-coded pictures.
         *
         * Results:
         *	The decoding table for macro_block_type in bidirectionally-coded
         *      pictures will be filled; illegal values will be filled as ERROR.
         *
         * Side effects:
         *	The global array mb_type_B will be filled.
         *
         *--------------------------------------------------------------
         */
        static void init_mb_type_B()
        {
            int i;

            mb_type_B[0].mb_quant = false;
            mb_type_B[0].mb_motion_forward 
              = mb_type_B[0].mb_motion_backward = mb_type_B[0].mb_pattern 
              = mb_type_B[0].mb_intra = false;
            mb_type_B[0].num_bits = 0;

            ASSIGN2(1, 2, 1, 0, 0, 0, 1, 6, mb_type_B);
            ASSIGN2(2, 3, 1, 0, 1, 1, 0, 6, mb_type_B);
            ASSIGN2(3, 4, 1, 1, 0, 1, 0, 6, mb_type_B);
            ASSIGN2(4, 6, 1, 1, 1, 1, 0, 5, mb_type_B);
            ASSIGN2(6, 8, 0, 0, 0, 0, 1, 5, mb_type_B);
            ASSIGN2(8, 12, 0, 1, 0, 0, 0, 4, mb_type_B);
            ASSIGN2(12, 16, 0, 1, 0, 1, 0, 4, mb_type_B);
            ASSIGN2(16, 24, 0, 0, 1, 0, 0, 3, mb_type_B);
            ASSIGN2(24, 32, 0, 0, 1, 1, 0, 3, mb_type_B);
            ASSIGN2(32, 48, 0, 1, 1, 0, 0, 2, mb_type_B);
            ASSIGN2(48, 64, 0, 1, 1, 1, 0, 2, mb_type_B);
        }


        /* Macro for filling up the decoding tables for motion_vectors */
        static int ASSIGN3(int start, int end, int step, int val, int num)
        {
            for (int i = start; i < end; i+= step)
            {
                for (int j = 0; j < step / 2; j++)
                {
                    motion_vectors[i+j].code = val;
                    motion_vectors[i+j].num_bits = num;
                }
                for (int j = step / 2; j < step; j++)
                {
                    motion_vectors[i+j].code = -val;
                    motion_vectors[i+j].num_bits = num;
                }
                val--;
            }
            return val;
        }



        /*
         *--------------------------------------------------------------
         *
         * init_motion_vectors --
         *
         *	Initialize the VLC decoding table for the various motion
         *      vectors, including motion_horizontal_forward_code, 
         *      motion_vertical_forward_code, motion_horizontal_backward_code,
         *      and motion_vertical_backward_code.
         *
         * Results:
         *	The decoding table for the motion vectors will be filled;
         *      illegal values will be filled as ERROR.
         *
         * Side effects:
         *	The global array motion_vector will be filled.
         *
         *--------------------------------------------------------------
         */
        static void init_motion_vectors()
        {
            int val = 16;

            for (int i = 0; i < 24; i++) {
                motion_vectors[i].code = ERROR;
                motion_vectors[i].num_bits = 0;
            }

            val = ASSIGN3(24, 36, 2, val, 11);
            val = ASSIGN3(36, 48, 4, val, 10);
            val = ASSIGN3(48, 96, 16, val, 8);
            val = ASSIGN3(96, 128, 32, val, 7);
            val = ASSIGN3(128, 256, 128, val, 5);
            val = ASSIGN3(256, 512, 256, val, 4);
            val = ASSIGN3(512, 1024, 512, val, 3);
            val = ASSIGN3(1024, 2048, 1024, val, 1);
        }

        /*
         *--------------------------------------------------------------
         *
         * decodeInitTables --
         *
         *	Initialize all the tables for VLC decoding; this must be
         *      called when the system is set up before any decoding can
         *      take place.
         *
         * Results:
         *	All the decoding tables will be filled accordingly.
         *
         * Side effects:
         *	The corresponding global array for each decoding table 
         *      will be filled.
         *
         *--------------------------------------------------------------
         */    
        public static void decodeInitTables()
        {
            init_mb_addr_inc();
            init_mb_type_P();
            init_mb_type_B();
            init_motion_vectors();

            MPEGnet.jrevdct.init_pre_idct();

        }
    }

    internal class VlcStaticInitializer
    {
        public VlcStaticInitializer()
        {
            VlcTables.decodeInitTables();
        }
    }
}
